package juc.c_020;
/*
   Talk is cheap. Show me the code.
 */

import java.util.Random;
import java.util.concurrent.locks.StampedLock;

/**
 * @Description
 * @Date 2021/6/20
 * @Author liudl
 */
public class T10_StampedLock {
    static StampedLock stampedLock = new StampedLock();
    static int count = 0;
    double x = 0, y = 0;

    static void read() {
        long stamp = stampedLock.readLock();
        try {
            Thread.sleep(200);
            System.out.println("count = " + count);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            stampedLock.unlock(stamp);
        }
    }

    static void write(int value) {
        long stamp = stampedLock.writeLock();
        try {
            count += value;
            System.out.println("write.");
        } finally {
            stampedLock.unlock(stamp);
        }
    }

    public void moveIfAt(double oldX, double oldY, double newX, double newY) {
        //获得一个读悲观锁
        long stamp = stampedLock.readLock();
        try {
            //循环，检查当前状态是否符合
            while (x == oldX && y == oldY) {
                //将读锁转为写锁
                long writeStamp = stampedLock.tryConvertToWriteLock(stamp);
                //这是确认转为写锁是否成功
                if (writeStamp != 0L) {
                    //如果成功 替换票据
                    stamp = writeStamp;
                    x = newX;
                    //进行状态改变
                    y = newY;
                    break;
                } else {
                    //如果不能成功转换为写锁
                    //我们显式释放读锁
                    stampedLock.unlockRead(stamp);
                    //显式直接进行写锁 然后再通过循环再试
                    stamp = stampedLock.writeLock();
                }
            }
        } finally {
            //释放读锁或写锁
            stampedLock.unlock(stamp);
        }
    }
    public double distanceFromOrigin() {
        //获得一个乐观读锁
        long stamp = stampedLock.tryOptimisticRead();
        //将两个字段读入本地局部变量
        double currentX = x, currentY = y;
        //检查发出乐观读锁后同时是否有其他写锁发生？
        if (!stampedLock.validate(stamp)) {
            //如果没有，我们再次获得一个读悲观锁
            stamp = stampedLock.readLock();
            try {
                // 将两个字段读入本地局部变量
                currentX = x;
                currentY = y;
            } finally {
                //释放读锁
                stampedLock.unlockRead(stamp);
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }

    public static void main(String[] args) {
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                write(new Random().nextInt(100));
            }).start();
        }
        for (int i = 0; i < 18; i++) {
            new Thread(() -> read()).start();
        }
    }
}
